﻿using System.Collections.Generic;
using MdxLib.Animator;
using MdxLib.Model;
using MdxLib.Primitives;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Graphics;
using System;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;

namespace XNADota.ContentPipeline.MDX
{
    public enum EMdxInterpolationType 
    {
        None,
        Linear,
        Bezier, 
        Hermite,
    }

    public enum EMdxMaterialLayerFilterMode
    {
        None,
        Transparent,
        Blend, 
        Additive,
        AdditiveAlpha,
        Modulate,
        Modulate2x,
    }

    public enum EMdxCollisionShape
    {
        Box,
        Sphere,
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Model, XNADota")]
    public class ModelContent
    {
        public string Name = null;
        public List<SequenceContent> Sequences = null;
        public List<TextureMDXContent> Textures = null;
        public List<MaterialContent> Materials = null;
        public List<GeosetContent> Geosets = null;
        public List<BoneContent> Bones = null;
        public List<HelperContent> Helpers = null;
        public List<GeosetAnimationContent> GeosetAnimations = null;
        public List<AttachmentContent> Attachments = null;
        public List<CollisionShapeContent> CollisionShapes = null;
        public List<CameraContent> Cameras = null;
        public List<LightContent> Lights = null;
        public List<ParticleEmitterContent> ParticleEmitters = null;
        public List<ParticleEmitter2Content> ParticleEmitter2s = null;
        public List<RibbonEmitterContent> RibbonEmitters = null;
        public List<EventObjectContent> EventObjects = null;
        public List<TextureAnimationContent> TextureAnimations = null;

        public ModelContent(CModel input, ContentProcessorContext context)
        {
            Name = input.Name;

            this.Sequences = new List<SequenceContent>();
            this.Textures = new List<TextureMDXContent>();
            this.Materials = new List<MaterialContent>();
            this.Geosets = new List<GeosetContent>();
            this.Bones = new List<BoneContent>();
            this.Helpers = new List<HelperContent>();
            this.GeosetAnimations = new List<GeosetAnimationContent>();
            this.Attachments = new List<AttachmentContent>();
            this.CollisionShapes = new List<CollisionShapeContent>();
            this.Cameras = new List<CameraContent>();
            this.Lights = new List<LightContent>();
            this.ParticleEmitters = new List<ParticleEmitterContent>();
            this.ParticleEmitter2s = new List<ParticleEmitter2Content>();
            this.RibbonEmitters = new List<RibbonEmitterContent>();
            this.EventObjects = new List<EventObjectContent>();
            this.TextureAnimations = new List<TextureAnimationContent>();

            #region Basic Graphcis, including vertices, material, and textures
            // create geosets
            this.Textures.Clear();
            if (input.HasTextures)
            {
                for (int textureIndex = 0; textureIndex < input.Textures.Count; textureIndex++)
                {
                    this.Textures.Add(new TextureMDXContent(input.Textures[textureIndex], context));
                }
            }
            else
            {
                throw new InvalidContentException("MDX file does not contain textures.");
            }

            // load materials
            this.Materials.Clear();
            if (input.HasMaterials)
            {
                for (int materialIndex = 0; materialIndex < input.Materials.Count; materialIndex++)
                {
                    this.Materials.Add((new MaterialContent(input.Materials[materialIndex])));
                }
            }

            // load geometries
            this.Geosets.Clear();
            if (input.HasGeosets)
            {
                for (int GeosetIndex = 0; GeosetIndex < input.Geosets.Count; GeosetIndex++)
                {
                    this.Geosets.Add(new GeosetContent(input.Geosets[GeosetIndex]));
                }
            }
            else
            {
                throw new InvalidContentException("MDX file does not contain information of geometry set.");
            }
            #endregion

            #region Bone and geoset animation
            // load animation information
            this.Sequences.Clear();
            if (input.HasSequences)
            {
                int SequenceCount = input.Sequences.Count;
                for (int sequenceIndex = 0; sequenceIndex < SequenceCount; sequenceIndex++)
                {
                    this.Sequences.Add(new SequenceContent(input.Sequences[sequenceIndex]));
                }
            }
            else
            {
                throw new InvalidContentException("MDX file does not contain animation sequences.");
            }

            // load bones
            this.Bones.Clear();
            if (input.HasBones)
            {
                int boneCount = input.Bones.Count;
                for (int boneIndex = 0; boneIndex < boneCount; boneIndex++)
                {
                    this.Bones.Add(new BoneContent(input.Bones[boneIndex]));
                }
            }
            else
            {
                throw new InvalidContentException("MDX does not contain information of bones.");
            }

            // load helpers
            this.Helpers.Clear();
            if (input.HasHelpers)
            {
                int helperCount = input.Helpers.Count;
                for (int helperIndex = 0; helperIndex < helperCount; helperIndex++)
                {
                    this.Helpers.Add(new HelperContent(input.Helpers[helperIndex]));
                }
            }

            // GeosetAnimations
            this.GeosetAnimations.Clear();
            if (input.HasGeosetAnimations)
            {
                int geosetAnimationCount = input.GeosetAnimations.Count;
                for (int geosetAnimIndex = 0; geosetAnimIndex < geosetAnimationCount; geosetAnimIndex++)
                {
                    this.GeosetAnimations.Add(new GeosetAnimationContent(input.GeosetAnimations[geosetAnimIndex]));
                }
            }

            // load TextureAnimations
            if (input.HasTextureAnimations)
            {
                int textureAnimationCount = input.TextureAnimations.Count;
                for (int textureAnimationIndex = 0; textureAnimationIndex < textureAnimationCount; textureAnimationIndex++)
                {
                    this.GeosetAnimations.Add(new GeosetAnimationContent(input.GeosetAnimations[textureAnimationIndex]));
                }
            }
            #endregion

            #region Attachments, Collision shapes
            // load attachments
            if (input.HasAttachments)
            {
                int attachmentCount = input.Attachments.Count;
                for (int attachmentIndex = 0; attachmentIndex < attachmentCount; attachmentIndex++)
                {
                    this.Attachments.Add(new AttachmentContent(input.Attachments[attachmentIndex]));
                }
            }

            // load CollisionShapes
            if (input.HasCollisionShapes)
            {
                int collisionShapesCount = input.CollisionShapes.Count;
                for (int collisionShapeIndex = 0; collisionShapeIndex < collisionShapesCount; collisionShapeIndex++)
                {
                    this.CollisionShapes.Add(new CollisionShapeContent(input.CollisionShapes[collisionShapeIndex]));
                }
            }
            #endregion

            #region Particle Effects
            if (input.HasParticleEmitters) 
            {
                int particleEmitterCount = input.ParticleEmitters.Count;
                for (int particleEmitterIndex = 0; particleEmitterIndex < particleEmitterCount; particleEmitterIndex++)
                {
                    this.ParticleEmitters.Add(new ParticleEmitterContent(input.ParticleEmitters[particleEmitterIndex]));
                }
            }

            if (input.HasParticleEmitters2)
            {
                int particleEmitter2Count = input.ParticleEmitters2.Count;
                for (int particleEmitter2Index = 0; particleEmitter2Index < particleEmitter2Count; particleEmitter2Index++)
                {
                    this.ParticleEmitter2s.Add(new ParticleEmitter2Content(input.ParticleEmitters2[particleEmitter2Index]));
                }
            }

            if (input.HasRibbonEmitters)
            {
                int ribbonEmitterCount = input.RibbonEmitters.Count;
                for (int ribbonEmitterIndex = 0; ribbonEmitterIndex < ribbonEmitterCount; ribbonEmitterIndex++)
                {
                    this.RibbonEmitters.Add(new RibbonEmitterContent(input.RibbonEmitters[ribbonEmitterIndex]));
                }
            }

            if (input.HasEvents)
            {
                int eventObjectCount = input.Events.Count;
                for (int eventObjectIndex = 0; eventObjectIndex < eventObjectCount; eventObjectIndex++)
                {
                    this.EventObjects.Add(new EventObjectContent(input.Events[eventObjectIndex]));
                }
            }
            #endregion

            #region Scene Objects
            if (input.HasCameras)
            {
                int cameraCount = input.Cameras.Count;
                for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) 
                {
                    this.Cameras.Add(new CameraContent(input.Cameras[cameraIndex]));
                }
            }

            if (input.HasLights)
            {
                int LightCount = input.Lights.Count;
                for (int lightIndex = 0; lightIndex < LightCount; lightIndex ++)
                {
                    this.Lights.Add(new LightContent(input.Lights[lightIndex]));
                }
            }
            #endregion
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Sequence, XNADota")]
    public class SequenceContent
    {
        public int SequenceID;
        public ExtentContent Extent;
        public int IntervalStart;
        public int IntervalEnd;
        public float MoveSpeed;
        public float Rarity;
        public bool NonLooping;
        public string Name;
        public int SyncPoint;

        public SequenceContent(CSequence sequence)
        {
            this.SequenceID = sequence.ObjectId;
            this.Extent = new ExtentContent(sequence.Extent);
            this.IntervalStart = sequence.IntervalStart;
            this.IntervalEnd = sequence.IntervalEnd;
            this.MoveSpeed = sequence.MoveSpeed;
            this.Rarity = sequence.Rarity;
            this.NonLooping = sequence.NonLooping;
            this.Name = sequence.Name;
            this.SyncPoint = sequence.SyncPoint;
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.MdxTexture, XNADota")]
    public class TextureMDXContent
    {
        public int TextureID;
        public int ReplaceableId;
        public ExternalReference<TextureContent> Texture;

        public TextureMDXContent(CTexture texture, ContentProcessorContext context)
        {
            this.TextureID = texture.ObjectId;
            this.ReplaceableId = texture.ReplaceableId;
            if (texture.FileName.Trim().Length > 0)
            {
                string fileName = texture.FileName.Trim().Replace(SHelper.MDX_WARCRAFT_IMAGE_FILE_SUFFIX, SHelper.IMAGE_FILE_SUFFIX);
                this.Texture = context.BuildAsset<TextureContent, TextureContent>
                    (new ExternalReference<TextureContent>(fileName), SHelper.TEXTURE_PROCESSOR_NAME);
            }
            else
            {
                this.Texture = null;
            }
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Material, XNADota")]
    public class MaterialContent
    {
        public int MaterialID;
        public LayerContent[] LayerContents;

        public MaterialContent(CMaterial material)
        {
            this.MaterialID = material.ObjectId;
            if (material.HasLayers)
            {
                int LayerCount = material.Layers.Count;
                LayerContents = new LayerContent[LayerCount];
                for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
                {
                    LayerContents[layerIndex] = new LayerContent(material.Layers[layerIndex]);
                }
            }
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Layer, XNADota")]
    public class LayerContent
    {
        public EMdxMaterialLayerFilterMode FilterMode;
        public int CellTextureId;

        public LayerContent(CMaterialLayer MaterialLayer)
        {
            this.FilterMode = (EMdxMaterialLayerFilterMode)Enum.ToObject(typeof(EMdxMaterialLayerFilterMode), (int)MaterialLayer.FilterMode);
            if (MaterialLayer.Texture != null)
                this.CellTextureId = MaterialLayer.Texture.ObjectId;
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Geoset, XNADota")]
    public class GeosetContent
    {
        public int GeosetID;
        public int MaterialID;

        // faces and vertices
        public int TriangleCount;
        public int VerticesCount;
        public VertexPositionNormalTexture[] Vertices;
        public int[] Indices;

        // group information
        public int[] VertexGroupID;
        public List<int>[] GeosetGroups;

        public GeosetContent(CGeoset geoset)
        {
            this.GeosetID = geoset.ObjectId;
            this.MaterialID = geoset.Material.ObjectId;

            // read vertices in {position, normal, texture}
            this.VerticesCount = geoset.Vertices.Count;
            this.Vertices = new VertexPositionNormalTexture[VerticesCount];
            this.VertexGroupID = new int[VerticesCount];
            for (int j = 0; j < VerticesCount; j++)
            {
                CGeosetVertex v = geoset.Vertices[j];
                Vector3 vertex = new Vector3(v.Position.X, v.Position.Y, v.Position.Z);
                Vector3 normal = new Vector3(v.Normal.X, v.Normal.Y, v.Normal.Z);
                Vector2 uv = new Vector2(v.TexturePosition.X, v.TexturePosition.Y);

                this.Vertices[j] = new VertexPositionNormalTexture(vertex, normal, uv);

                VertexGroupID[j] = v.Group.ObjectId;
            }

            // read Indices
            this.TriangleCount = geoset.Faces.Count;
            this.Indices = new int[TriangleCount * 3];
            for (int j = 0; j < TriangleCount * 3; j += 3)
            {
                this.Indices[j] = geoset.Faces[j / 3].Vertex1.ObjectId;
                this.Indices[j + 1] = geoset.Faces[j / 3].Vertex2.ObjectId;
                this.Indices[j + 2] = geoset.Faces[j / 3].Vertex3.ObjectId;
            }

            // read groups
            int groupCount = geoset.Groups.Count;
            GeosetGroups = new List<int>[groupCount];
            for (int i = 0; i < groupCount; i++)
            {
                GeosetGroups[i] = new List<int>();
                for (int j = 0; j < geoset.Groups[i].Nodes.Count; j++)
                {
                    GeosetGroups[i].Add(geoset.Groups[i].Nodes[j].Node.ObjectId);
                }
            }
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Vector4AnimatorNode, XNADota")]
    public class Vector4AnimatorNodeContent
    {
        public Vector4 Value;
        public Vector4 InTangent;
        public Vector4 OutTangent;
        public float Time;

        public Vector4AnimatorNodeContent(CAnimatorNode<CVector3> AnimatorNode)
        {
            this.Value = SHelper.GetVector4(AnimatorNode.Value);
            this.OutTangent = SHelper.GetVector4(AnimatorNode.Value);
            this.InTangent = SHelper.GetVector4(AnimatorNode.Value);
            this.Time = AnimatorNode.Time;
        }
        public Vector4AnimatorNodeContent(CAnimatorNode<CVector4> AnimatorNode)
        {
            this.Value = SHelper.GetVector4(AnimatorNode.Value);
            this.OutTangent = SHelper.GetVector4(AnimatorNode.Value);
            this.InTangent = SHelper.GetVector4(AnimatorNode.Value);
            this.Time = AnimatorNode.Time;
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Vector4Animator, XNADota")]
    public class Vector4AnimatorContent
    {
        public Vector4AnimatorNodeContent[] Vector4AnimatorNodeContents;
        public EMdxInterpolationType Type;

        public Vector4AnimatorContent(CAnimator<CVector3> animator)
        {
            Type = (EMdxInterpolationType)Enum.ToObject(typeof(EMdxInterpolationType), (int)animator.Type);
            int count = animator.Count;
            Vector4AnimatorNodeContents = new Vector4AnimatorNodeContent[count];
            for (int i = 0; i < count; i++)
                Vector4AnimatorNodeContents[i] = new Vector4AnimatorNodeContent(animator[i]);
        }

        public Vector4AnimatorContent(CAnimator<CVector4> animator)
        {
            Type = (EMdxInterpolationType)Enum.ToObject(typeof(EMdxInterpolationType), (int)animator.Type);
            int count = animator.Count;
            Vector4AnimatorNodeContents = new Vector4AnimatorNodeContent[count];
            for (int i = 0; i < count; i++)
                Vector4AnimatorNodeContents[i] = new Vector4AnimatorNodeContent(animator[i]);
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Extent, XNADota")]
    public class ExtentContent
    {
        public ExtentContent(CExtent extent)
        {
            Min = SHelper.GetVector3(extent.Min);
            Max = SHelper.GetVector3(extent.Max);
            Radius = extent.Radius;
        }

        public Vector3 Min;
        public Vector3 Max;
        public float Radius;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Bone, XNADota")]
    public class BoneContent : NodeContent<BoneContent>
    {
        public int GeosetId;
        public int GeosetAnimationId;

        public BoneContent(CBone bone)
            : base(bone)
        {
            this.GeosetId = bone.Geoset.ObjectId;
            this.GeosetAnimationId = bone.GeosetAnimation.ObjectId;
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Helper, XNADota")]
    public class HelperContent : NodeContent<HelperContent>
    {
        public HelperContent(CHelper helper)
            : base(helper)
        {
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Node, XNADota")]
    public class NodeContent<T> where T : NodeContent<T>
    {
        public NodeContent(INode node)
        {
            this.Name = node.Name;
            // basic information
            this.NodeID = node.NodeId;
            this.ParentNodeID = node.Parent.NodeId;
            this.PivorPoint = SHelper.GetVector3(node.PivotPoint);

            // get translation
            this.TranslationContent = new Vector4AnimatorContent(node.Translation);
            this.RotationContent = new Vector4AnimatorContent(node.Rotation);
            this.ScalingContent = new Vector4AnimatorContent(node.Scaling);
        }
        public string Name;
        public int NodeID;
        public int ParentNodeID;
        public Vector3 PivorPoint;
        public Vector4AnimatorContent TranslationContent;
        public Vector4AnimatorContent RotationContent;
        public Vector4AnimatorContent ScalingContent;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.GeosetAnimation, XNADota")]
    public class GeosetAnimationContent
    {
        public GeosetAnimationContent(CGeosetAnimation GeosetAnimation)
        {
            this.GeosetAnimationId = GeosetAnimation.ObjectId;
            this.GeosetId = GeosetAnimation.Geoset.ObjectId;
            this.AlphaAnimatorContent = new FloatAnimatorContent(GeosetAnimation.Alpha);
        }

        public int GeosetAnimationId;
        public int GeosetId;
        public FloatAnimatorContent AlphaAnimatorContent;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.FloatAnimator, XNADota")]
    public class FloatAnimatorContent
    {
        public FloatAnimatorContent(CAnimator<float> floatAnimator)
        {
            this.Type = (EMdxInterpolationType)Enum.ToObject(typeof(EMdxInterpolationType), (int)floatAnimator.Type);
            int floatNodesCount = floatAnimator.Count;
            AlphaAnimatorNodeContents = new FloatAnimatorNodeContent[floatNodesCount];
            for (int i = 0; i < floatNodesCount; i++)
                AlphaAnimatorNodeContents[i] = new FloatAnimatorNodeContent(floatAnimator[i]);
        }

        public FloatAnimatorNodeContent[] AlphaAnimatorNodeContents;
        public EMdxInterpolationType Type;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.FloatAnimatorNode, XNADota")]
    public class FloatAnimatorNodeContent
    {
        public FloatAnimatorNodeContent(CAnimatorNode<float> floatNode)
        {
            this.Time = floatNode.Time;
            this.Value = floatNode.Value;
            this.InTangent = floatNode.InTangent;
            this.OutTangent = floatNode.OutTangent;
        }

        public int Time;
        public float Value;
        public float InTangent;
        public float OutTangent;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Attachment, XNADota")]
    public class AttachmentContent : NodeContent<AttachmentContent>
    {
        public AttachmentContent(CAttachment attachment)
            : base(attachment)
        {
            this.AttachmentId = attachment.AttachmentId;
            this.Path = attachment.Path;
            this.Visibility = new FloatAnimatorContent(attachment.Visibility);
        }

        public int AttachmentId;
        public string Path;
        public FloatAnimatorContent Visibility;
    }


    [ContentSerializerRuntimeType("XNADota.MDX.CollisionShape, XNADota")]
    public class CollisionShapeContent : NodeContent<CollisionShapeContent>
    {
        public CollisionShapeContent(CCollisionShape collisionShape)
            : base(collisionShape)
        {
            this.CollisionShapeId = collisionShape.ObjectId;
            this.Type = (EMdxCollisionShape)Enum.ToObject(typeof(EMdxCollisionShape), collisionShape.Type);
            this.Vertex1 = SHelper.GetVector3(collisionShape.Vertex1);
            this.Vertex2 = SHelper.GetVector3(collisionShape.Vertex2);
            this.Radius = collisionShape.Radius;
        }

        public int CollisionShapeId;
        public EMdxCollisionShape Type;
        public Vector3 Vertex1;
        public Vector3 Vertex2;
        public float Radius;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Light, XNADota")]
    public class LightContent : NodeContent<LightContent>
    {
        public LightContent(CLight light)
            : base(light)
        {
            //light.AmbientColor;
            //light.AmbientIntensity;
            //light.AttenuationEnd;
            //light.AttenuationStart;
            //light.Color;
            //light.Intensity;
            this.ObjectId = light.ObjectId;
        }

        public int ObjectId;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.ParticleEmitter, XNADota")]
    public class ParticleEmitterContent : NodeContent<ParticleEmitterContent>
    {
        public ParticleEmitterContent(CParticleEmitter particleEmitter)
            : base(particleEmitter)
        {
            EmissionRate = new FloatAnimatorContent(particleEmitter.EmissionRate);
            LifeSpan = new FloatAnimatorContent(particleEmitter.LifeSpan);
            Gravity = new FloatAnimatorContent(particleEmitter.Gravity);
            InitialVelocity = new FloatAnimatorContent(particleEmitter.InitialVelocity);
            Latitude = new FloatAnimatorContent(particleEmitter.Latitude);
            Longitude = new FloatAnimatorContent(particleEmitter.Longitude);
            Visibility = new FloatAnimatorContent(particleEmitter.Visibility);

            EmitterUsesMdl = particleEmitter.EmitterUsesMdl;
            EmitterUsesTga = particleEmitter.EmitterUsesTga;
            FileName = particleEmitter.FileName;
        }

        public FloatAnimatorContent EmissionRate;
        public FloatAnimatorContent LifeSpan;
        public FloatAnimatorContent Gravity;
        public FloatAnimatorContent InitialVelocity;
        public FloatAnimatorContent Latitude;
        public FloatAnimatorContent Longitude;
        public FloatAnimatorContent Visibility;

        public bool EmitterUsesMdl;
        public bool EmitterUsesTga;
        public string FileName;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.ParticleEmitter2, XNADota")]
    public class ParticleEmitter2Content : NodeContent<ParticleEmitter2Content>
    {
        public ParticleEmitter2Content(CParticleEmitter2 particleEmitter2)
            : base(particleEmitter2)
        {
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.RibbonEmitter, XNADota")]
    public class RibbonEmitterContent : NodeContent<RibbonEmitterContent>
    {
        public RibbonEmitterContent(CRibbonEmitter ribbonEmitter)
            : base(ribbonEmitter)
        {
        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.EventObject, XNADota")]
    public class EventObjectContent : NodeContent<EventObjectContent>
    {
        public EventObjectContent(CEvent eventObject)
            : base(eventObject)
        {

        }
    }

    [ContentSerializerRuntimeType("XNADota.MDX.Camera, XNADota")]
    public class CameraContent
    {
        public CameraContent(CCamera camera)
        {
            this.ObjectId = camera.ObjectId;
            this.FarDistance = camera.FarDistance;
            this.FieldOfView = camera.FieldOfView;
            this.NearDistance = camera.NearDistance;
            this.Position = SHelper.GetVector3(camera.Position);
            //camera.Rotation;
            this.TargetPosition = SHelper.GetVector3(camera.TargetPosition);
            //camera.TargetTranslation;
            this.Name = camera.Name;
            //camera.Translation;
        }

        public int ObjectId;
        public float FarDistance;
        public float FieldOfView;
        public float NearDistance;
        public Vector3 Position;
        public Vector3 TargetPosition;
        public string Name;
    }

    [ContentSerializerRuntimeType("XNADota.MDX.TextureAnimation, XNADota")]
    public class TextureAnimationContent
    {
        public TextureAnimationContent(CTextureAnimation textureAnimation)
        {
        }
    }

    public static class SHelper
    {
        public const string TEXTURE_PROCESSOR_NAME = "TextureProcessor";
        public const string MDX_WARCRAFT_IMAGE_FILE_SUFFIX = ".blp";
        public const string IMAGE_FILE_SUFFIX = ".tga";

        public static Vector3 GetVector3(CVector3 CVector3)
        {
            return new Vector3(CVector3.X, CVector3.Y, CVector3.Z);
        }

        public static Vector4 GetVector4(CVector3 CVector3)
        {
            return new Vector4(CVector3.X, CVector3.Y, CVector3.Z, 0);
        }

        public static Vector4 GetVector4(CVector4 CVector4)
        {
            return new Vector4(CVector4.X, CVector4.Y, CVector4.Z, CVector4.W);
        }
    }
}
